﻿using DotNetExtensions.AspNet;
using DotNetExtensions.AspNet.Encryptions;
using DotNetExtensions.AspNet.Events;
using DotNetExtensions.AspNet.HttpClients;
using Newtonsoft.Json;
using Habi.Solver.Helpers;
using Habi.Solver.Models;
using Habi.Solver.Models.Resources;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Habi.Solver.Common
{
    public class TaskUploader : Singleton<TaskUploader>
    {
        private readonly Dictionary<long, ResourceTaskModel> __TASK__ = new Dictionary<long, ResourceTaskModel>();

        private readonly Dictionary<long, IHttpClient> FileHttpClient = new Dictionary<long, IHttpClient>();

        public event TransferTaskEvent OnTaskCompleted;
        public event TransferTaskEvent OnTaskProgressChanged;

        public readonly string UploadFileUrl;

        private TaskUploader()
        {
            UploadFileUrl = AppEnvironment.Default.UploadServerUrl;
        }

        public void Start(ResourceTaskModel task)
        {
            //Task.Factory.StartNew();
            lock (mutex)
            {
                if (__TASK__.ContainsKey(task.Id)) return;

                __TASK__.Add(task.Id, task);

                HttpRequestStart(task);
            }
        }

        private void HttpRequestStart(ResourceTaskModel task)
        {
            try
            {
                IHttpClient fileHttpClient = new FileHttpRequest();
                fileHttpClient.Before += (url, e) =>
                  {
                      if (!File.Exists(task.Url))
                      {
                          e.Cancel = true;
                          e.ErrorMessage = $"The specified file does not exist `{task.Url}`";
                      }
                      else
                      {
                          task.Status = (int)ResourceTaskStatus.Uploading;
                          OnTaskProgressChanged?.Invoke(new TaskEventArgs(task));

                          var fe = (e as FileTransferArgs);
                          fe.ExtraData = task;
                          fe.FileName = task.Url;
                      }
                  };

                fileHttpClient.Progress += (url, e) =>
                  {
                      task.Progress = (e as FileTransferArgs).Progress;
                      OnTaskProgressChanged?.Invoke(new TaskEventArgs(task));
                  };

                fileHttpClient.Completed += (url, e) =>
                  {
                      task.Status = (int)ResourceTaskStatus.Downloaded;
                      OnTaskCompleted?.Invoke(new TaskEventArgs(task, "", "", true));
                  };

                fileHttpClient.PostAsync(UploadFileUrl, null);

                FileHttpClient.Add(task.Id, fileHttpClient);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Task upload error, msg: {0}", ex.Message);
                task.Status = (int)ResourceTaskStatus.Error;
                OnTaskCompleted?.Invoke(new TaskEventArgs(task));
            }
        }

        public void Pause(ResourceTaskModel task)
        {
            lock (mutex)
            {
                if (!FileHttpClient.ContainsKey(task.Id)) return;
                FileHttpClient[task.Id].Cancel();
            }
        }

        public void Delete(ResourceTaskModel task)
        {
            lock (mutex)
            {
                if (!FileHttpClient.ContainsKey(task.Id)) return;
                FileHttpClient[task.Id].Cancel();
                __TASK__.Remove(task.Id);
            }
        }
    }
}
